package graphNeo4j

import org.neo4j.graphdb.GraphDatabaseService
import org.neo4j.graphdb.Node
import org.neo4j.graphdb.traversal.TraversalDescription
import org.neo4j.kernel.impl.traversal.TraversalDescriptionImpl
import javax.persistence.Entity
import org.neo4j.graphdb.Direction
import org.neo4j.graphdb.traversal.Evaluators
import org.neo4j.graphdb.traversal.Traverser
import scala.collection.JavaConverters._
import scala.collection.JavaConversions._
import scala.collection.mutable.Buffer
import org.neo4j.graphdb.Relationship
import primeraEntregaMain.Usuario
import org.neo4j.graphdb.index.Index

object UserNodeService {
	def getUserNode(usuario: Usuario): Node = {
		Graph.withTransaction[Node] { () =>
			var g: GraphDatabaseService = Graph.getSession
	        var nodes = g.index().forNodes("users").query("userName", usuario.getNombreDeUsuario)
	        nodes.next
		}
	}
	
	def createUserNode(usuario: Usuario) {
		Graph.withTransaction[Unit] { () =>
			var userNode: Node = Graph.getSession.createNode
			userNode.setProperty("userName", usuario.getNombreDeUsuario)
			var indexes: Index[Node] = Graph.getSession().index().forNodes("users")
	        indexes.add(userNode, "userName", usuario.getNombreDeUsuario)
		}
	}
	
	def createMessageNode(mensaje: String): Node = {
		Graph.withTransaction[Node] { () =>
			var g: GraphDatabaseService = Graph.getSession
			var node: Node = g.createNode
			node.setProperty("mensaje", mensaje)
			node
		}
	}
	
	/**
	 * Crea la relacion entre el usuario receptor y el pasado como parametro
	 */
	def agregarAmigo(usuario: Usuario, amigo: Usuario): Relationship = {
		Graph.withTransaction[Relationship] { () =>
		    var userNode: Node = UserNodeService.getUserNode(usuario)
	        var friendNode: Node = UserNodeService.getUserNode(amigo)
	        userNode.createRelationshipTo(friendNode, UserRelation.KNOWS)
		}
	}
	
	/**
	  * Devuelve la lista de todos los amigos del usuario
	 */
	def consultarAmigos(usuario: Usuario): Buffer[String] = {
		Graph.withTransaction[Buffer[String]] { () =>
			var userNode: Node = getUserNode(usuario)
	        var nodes: java.util.List[String] = new java.util.ArrayList[String]
			
			userNode.getRelationships(UserRelation.KNOWS).foreach(x => nodes.add(x.getOtherNode(userNode).getProperty("userName").asInstanceOf[String]))
			
	        nodes
		}
	}
	
	/**
      * Crea un nodo mensaje y lo relaciona con el que envia y el que recibe
     */
	def enviarMensaje(mensaje: String, usuario: Usuario, amigo: Usuario) {
		Graph.withTransaction[Unit] { () =>
			var g: GraphDatabaseService = Graph.getSession
			var messageNode: Node = createMessageNode(mensaje)
			var userNode: Node = getUserNode(usuario)
			var friendNode: Node = getUserNode(amigo)
			
			userNode.createRelationshipTo(messageNode, UserRelation.SENDER)
			friendNode.createRelationshipTo(messageNode, UserRelation.RECEIVER)
		}
	}

	/**
      * Devuelve una lista con los amigos del usuario y los amigos de sus amigos
     */
	def consultarAmigosDeAmigos(usuario: Usuario): Buffer[String] = {
		Graph.withTransaction[Buffer[String]] { () =>
			var g: GraphDatabaseService = Graph.getSession
			var td: TraversalDescription = new TraversalDescriptionImpl
			var breadthFirst = td.breadthFirst
			.relationships(UserRelation.KNOWS, Direction.OUTGOING)
			.evaluator(Evaluators.excludeStartPosition())
			
			var userNode: Node = getUserNode(usuario)
			var t: Traverser = breadthFirst.traverse(userNode)
			
			var nombres: java.util.List[String] = new java.util.ArrayList[String]
							
			t.nodes.foreach(x => nombres.add(x.getProperty("userName").asInstanceOf[String]))
						
			nombres
		}
	}
	
	/**
      * Devuelve los mensajes recibidos del usuario
     */
	def getMessagesReceive(usuario: Usuario): Buffer[String] = {
		Graph.withTransaction[Buffer[String]]{() =>
		    var userNode: Node = getUserNode(usuario)
	        var nodes: java.util.List[String] = new java.util.ArrayList[String]
			
			userNode.getRelationships(UserRelation.RECEIVER).foreach(x => nodes.add(x.getOtherNode(userNode).getProperty("mensaje").asInstanceOf[String]))
			nodes
		}	  
	}
	
	
}